/** 
Copyright (c) 2010, Sheikh Abdul Wahid Ahmed
Details @ http://extremecodeworld.codeplex.com/license
**/

using System;
using System.Collections;
using System.Data;
using EXtremecode.DataAccessLayer;
using System.Reflection;
namespace EXtremecode.BusinessLayer
{
	/// <summary>
	/// Summary description for BusinessBase.
	/// </summary>
	
	public delegate Hashtable  BOTypesRequiredDelegate(); 
	public class BusinessBase
	{
		private static Hashtable s_boTypes=null;
		private static DataSet s_dsDatabaseImage=new DataSet();
        public static BOTypesRequiredDelegate OnBOTypesRequired;
        
		private BusinessBase()
		{
			//
			// TODO: Add constructor logic here
			//
		}
		private static Hashtable BOTypes
		{
			get
			{
				if(s_boTypes==null)
				{
					if(OnBOTypesRequired==null)
						throw new Exception("[UE] BOTypes required for getting business object collections");
					else
						s_boTypes=OnBOTypesRequired();
				}
				return s_boTypes;
			}
		}
		public static BusinessObjectCollection GetBOCollection(string entityName)
		{
			Type type= BOTypes[entityName] as Type;
			if(type== null)
			{
				return null;
			}
			PropertyInfo propertyInfo=type.GetProperty("Collection");
			return  propertyInfo.GetValue(null,null) as BusinessObjectCollection;
			
		}

		public static BusinessObjectCollection GetNewBOCollection(string entityName)
		{
			Type type= BOTypes[entityName] as Type;
			if(type== null)
			{
				return null;
			}
			PropertyInfo propertyInfo=type.GetProperty("NewCollection");
			return  propertyInfo.GetValue(null,null) as BusinessObjectCollection;
			
		}
	
		private static DataSet DatabaseImage
		{
			get
			{
				return s_dsDatabaseImage.Clone();
			}
		}

		private static void AddTableAndItsRelations(BusinessObjectCollection col)
		{
			try
			{
				if(!s_dsDatabaseImage.Tables.Contains(col.Table_Name))
				{
					DataTable dt= col.GetDataTable();
					s_dsDatabaseImage.Tables.Add(dt);
					
					//Add Child Relations
					foreach(object key in col.ChildRelations.Keys)
					{
						BusinessObjectRelation rel = col.ChildRelations[key.ToString()];
						if(!s_dsDatabaseImage.Relations.Contains(rel.Name))//Relation should be added once
						{
							if(s_dsDatabaseImage.Tables.Contains(rel.ReferencedTable))//Referenced Table must exists
							{
								DataTable dtReferenced=s_dsDatabaseImage.Tables[rel.ReferencedTable];
								DataColumn[] dcsReferenced=new DataColumn[rel.ReferencedFields.Length]; 
								for(int i=0; i<dt.PrimaryKey.Length; i++)
								{
									dcsReferenced[i]= dtReferenced.Columns[rel.GetReferencedField(dt.PrimaryKey[i].ColumnName)];
								}
								DataRelation dataRel= s_dsDatabaseImage.Relations.Add(rel.Name,dt.PrimaryKey,dcsReferenced); 
							}
						}
					}
					//Add Parent Relations
					foreach(object key in col.ParentRelations.Keys)
					{
						BusinessObjectRelation rel = col.ParentRelations[key.ToString()];
						if(!s_dsDatabaseImage.Relations.Contains(rel.Name))//Relation should be added once
						{
							if(s_dsDatabaseImage.Tables.Contains(rel.ReferencedTable))//Referenced Table must exists
							{
								DataTable dtReferenced=s_dsDatabaseImage.Tables[rel.ReferencedTable];
								DataColumn[] dcsNative=new DataColumn[rel.NativeFields.Length];
								for(int i=0; i<dtReferenced.PrimaryKey.Length; i++)
								{
									dcsNative[i]= dt.Columns[rel.GetNativeField(dtReferenced.PrimaryKey[i].ColumnName)];
								}
								s_dsDatabaseImage.Relations.Add(rel.Name,dtReferenced.PrimaryKey,dcsNative); 
							}
						}
					}

				}
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				//Logging.Logger.Write();
			}
		}
		
	
		public static void Save(DataSet ds)
		{
			Save(ds,false);
		}

		public static void Save(DataSet ds,bool bIgnoreConcurrEx)
		{
			try
			{
								
				Hashtable htProcessedTables=new Hashtable();
				foreach(DataTable dt in ds.Tables)
				{
					UpdateTableRecursively(dt,htProcessedTables,bIgnoreConcurrEx);
				}
				DataAccessor.CommitTransaction();
				return;
			}
			catch(Exception ex)
			{
				DataAccessor.RollbackTransaction();
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				Logging.Logger.Write();
			}
		}
		private static void Fill()
		{
			Fill(s_dsDatabaseImage); 
		}
		public static void Fill(DataSet ds)
		{
			Fill(ds,false);
		}

		public static void Fill(DataSet ds,bool transactionBased)
		{
			try
			{
				
				Hashtable htProcessedTables=new Hashtable();
				foreach(DataTable dt in ds.Tables)
				{
					FillTableRecursively(dt,htProcessedTables,transactionBased);
				}
				DataAccessor.CommitTransaction();

				
			}
			catch(Exception ex)
			{
				DataAccessor.RollbackTransaction();
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				Logging.Logger.Write();
			}
		}


		private static void UpdateTableRecursively(DataTable dt,Hashtable htProcessedTables,bool bIgnoreConcurrEx)
		{
			try
			{
				if(htProcessedTables.Contains(dt.TableName))return;
			
				//This Statement should be here for avoiding Infinite loop in case of self relation.
				htProcessedTables.Add(dt.TableName,dt.TableName);
			
				foreach(DataRelation rel in  dt.ParentRelations)
				{
					UpdateTableRecursively(rel.ParentTable,htProcessedTables,bIgnoreConcurrEx);	
				}
				BusinessObjectCollection col= GetBOCollection(dt.TableName); 
				if(col!=null)col.UpdateDataTable(dt,true,bIgnoreConcurrEx);
			
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				//Logging.Logger.Write();
			}
		}
	

		private static void FillTableRecursively(DataTable dt,Hashtable htProcessedTables,bool transactionBased)
		{
			
			
			try
			{
				if(htProcessedTables.Contains(dt.TableName))return;
			
				//This Statement should be here for avoiding Infinite loop in case of self relation.
				htProcessedTables.Add(dt.TableName,dt.TableName);
			
				foreach(DataRelation rel in  dt.ParentRelations)
				{
					FillTableRecursively(rel.ParentTable,htProcessedTables,transactionBased);	
				}
				BusinessObjectCollection col= GetBOCollection(dt.TableName); 
				if(col!=null)col.FillDataTable(dt,transactionBased);
			
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				//Logging.Logger.Write();
			}
		}
	


	}
}
